package model

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

var _ EstateModel = (*customEstateModel)(nil)

type (
	// EstateModel is an interface to be customized, add more methods here,
	// and implement the added methods in customEstateModel.
	EstateModel interface {
		estateModel
		FindOneByName(ctx context.Context, name string) (*Estate, error)
		UpdateStatusById(ctx context.Context, id, status int64) error
		FindMaxSequenceNumberByStreet(ctx context.Context, street string) (int64, error)
		FindOneByCode(ctx context.Context, estateCode string) (*Estate, error)
	}

	customEstateModel struct {
		*defaultEstateModel
	}
)

// FindOneByCode 根据小区编号查询小区信息
func (c *customEstateModel) FindOneByCode(ctx context.Context, estateCode string) (*Estate, error) {
	var resp Estate
	query := fmt.Sprintf("select %s from %s where `estate_code` = ? limit 1", estateRows, c.table)
	err := c.QueryRowNoCacheCtx(ctx, &resp, query, estateCode)
	switch {
	case err == nil:
		return &resp, nil
	case errors.Is(err, sqlx.ErrNotFound):
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (c *customEstateModel) FindMaxSequenceNumberByStreet(ctx context.Context, street string) (int64, error) {
	var resp int64
	query := fmt.Sprintf("select coalesce(max(sequence_number), 0) from %s where `street` = ?", c.table)
	err := c.QueryRowNoCacheCtx(ctx, &resp, query, street)
	switch {
	case err == nil:
		return resp, nil
	case errors.Is(err, sqlx.ErrNotFound):
		return 0, nil
	default:
		return 0, err
	}
}

func (c *customEstateModel) UpdateStatusById(ctx context.Context, id, status int64) error {
	estateIdKey := fmt.Sprintf("%s%v", cacheEstateEstateIdPrefix, id)
	_, err := c.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
		query := fmt.Sprintf("update %s set %s where `id` = ?", c.table, "status=?")
		return conn.ExecCtx(ctx, query, status, id)
	}, estateIdKey)
	return err
}

func (c *customEstateModel) FindOneByName(ctx context.Context, estateName string) (*Estate, error) {
	var resp Estate
	query := fmt.Sprintf("select %s from %s where `estate_name` = ? limit 1", estateRows, c.table)
	err := c.QueryRowNoCacheCtx(ctx, &resp, query, estateName)
	switch {
	case err == nil:
		return &resp, nil
	case errors.Is(err, sqlx.ErrNotFound):
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

// NewEstateModel returns a model for the database table.
func NewEstateModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) EstateModel {
	return &customEstateModel{
		defaultEstateModel: newEstateModel(conn, c, opts...),
	}
}
